#include "backend_x.h"
#include <X11/Xlib.h>
#include <X11/extensions/XInput2.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

const char *buttonName(int button)
{
    switch (button) {
    case 1:
        return "Left";
    case 2:
        return "Middle";
    case 3:
        return "Right";
    case 4:
        return "Wheel Up";
    case 5:
        return "Wheel Down";
    case 6:
        return "Wheel Left";
    case 7:
        return "Wheel Right";
    case 8:
        return "Back";
    case 9:
        return "Forward";
    case 10:
        return "Task";
    default:
        return "Unknown";
    }
}
static volatile sig_atomic_t stop = 0;

static void sighandler(int signal, siginfo_t *siginfo, void *userdata)
{
    printf("xxx Signal received: %d\n", signal);
    stop = 1;
}

int backend_x()
{
    Display *display;
    XIEventMask mask;
    XIEventMask *masks;
    XIDeviceInfo *info;
    XEvent event;
    int xi_opcode;
    int event_type, event_code;
    int num_devices;

    display = XOpenDisplay(NULL);
    if (!display) {
        fprintf(stderr, "Failed to open X display\n");
        return 1;
    }

    int ievent, error;
    if (!XQueryExtension(display, "XInputExtension", &xi_opcode, &ievent, &error)) {
        printf("X Input extension not available.");
        return 1;
    }

    int major = 2, minor = 0;
    if (XIQueryVersion(display, &major, &minor) == BadRequest) {
        fprintf(stderr, "XInput2 not available\n");
        XCloseDisplay(display);
        return 1;
    }

    mask.deviceid = XIAllDevices;
    mask.mask_len = XIMaskLen(XI_LASTEVENT);
    mask.mask = (unsigned char *)calloc(mask.mask_len, sizeof(unsigned char));
    if (!mask.mask) {
        fprintf(stderr, "Failed to allocate mask for all device\n");
    }
    XISetMask(mask.mask, XI_ButtonPress);
    XISetMask(mask.mask, XI_ButtonRelease);
    XISetMask(mask.mask, XI_DeviceChanged);
    if (mask.deviceid == XIAllDevices)
        XISetMask(mask.mask, XI_HierarchyChanged);
    XISetMask(mask.mask, XI_PropertyEvent);
    masks = &mask;
    XISelectEvents(display, DefaultRootWindow(display), masks, 1);

    free(mask.mask);

    XSync(display, False);

    while (!stop) {
        XNextEvent(display, &event);
        if (XGetEventData(display, &event.xcookie)) {
            if (event.xcookie.evtype == XI_ButtonPress || event.xcookie.evtype == XI_ButtonRelease) {
                event_type = event.xcookie.evtype;
                XIDeviceEvent *dev = (XIDeviceEvent *)event.xcookie.data;
                event_code = dev->detail;
                printf("[x] Mouse[%02d] %s event detected for button (%s)\n",
                       dev->deviceid,
                       event_type == XI_ButtonPress ? "press  " : "release",
                       buttonName(event_code));
            }
            XFreeEventData(display, &event.xcookie);
        }
    }

    return 0;
}
